#ifndef SERVLET_H
#define SERVLET_H

#include <cstdint>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
#include <functional>
#include <shared_mutex>
#include <map>

#include <boost/asio.hpp>
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>

class Servlet
{
public:
    using ptr = std::shared_ptr<Servlet>;
    using RequestPtr = std::shared_ptr<boost::beast::http::request<boost::beast::http::dynamic_body>>;
    using ResponsePtr = std::shared_ptr<boost::beast::http::response<boost::beast::http::dynamic_body>>;

    Servlet(const std::string& name = ""):m_name(name) {} 
    virtual ~Servlet() {}

    /**
     * @brief 处理请求
     * @param[in] request HTTP请求
     * @param[in] response HTTP响应
     * @param[in] session HTTP连接
     * @return 是否处理成功
     */
    virtual int32_t handle(RequestPtr request
                ,ResponsePtr response) = 0;

    //返回servlet名称
    const std::string& getName() const { return m_name; }
private:
    std::string m_name;
};


//函数式 Servlet
class FunctionServlet: public Servlet
{
public:
    using ptr = std::shared_ptr<FunctionServlet>;
    using callback = std::function<int32_t(RequestPtr request
                                  ,ResponsePtr response)>;
    
    FunctionServlet(callback cb);

    int32_t handle(RequestPtr request
                ,ResponsePtr response) override;
private:
    callback m_cb;
};


class IServletCreator {
public:
    typedef std::shared_ptr<IServletCreator> ptr;
    virtual ~IServletCreator() {}
    virtual Servlet::ptr get() const = 0;
    virtual std::string getName() const = 0;
};

class HoldServletCreator : public IServletCreator {
public:
    typedef std::shared_ptr<HoldServletCreator> ptr;
    HoldServletCreator(Servlet::ptr slt)
        :m_servlet(slt) {
    }

    Servlet::ptr get() const override {
        return m_servlet;
    }

    std::string getName() const override {
        return m_servlet->getName();
    }
private:
    Servlet::ptr m_servlet;
};


template<class T>
class ServletCreator : public IServletCreator {
public:
    typedef std::shared_ptr<ServletCreator> ptr;

    ServletCreator() {
    }

    Servlet::ptr get() const override {
        return Servlet::ptr(new T);
    }

    std::string getName() const override {
        // return TypeToName<T>();
        return "";
    }
};

class ServletDispatch: public Servlet
{
public:
    using ptr = std::shared_ptr<ServletDispatch>;

    ServletDispatch();

    int32_t handle(RequestPtr request
                ,ResponsePtr response) override;

    //添加servlet
    void addServlet(const std::string& path, Servlet::ptr slt);
    void addServlet(const std::string& path, FunctionServlet::callback cb);
    
    //添加模糊匹配servlet
    void addGlobServlet(const std::string& path, Servlet::ptr slt);
    void addGlobServlet(const std::string& path, FunctionServlet::callback cb);

    //删除servlet
    void delServlet(const std::string& path);
    void delGlobServlet(const std::string& path);

    //返回默认servlet
    Servlet::ptr getDefault() const { return m_default;}
    //设置默认servlet
    void setDefault(Servlet::ptr v) { m_default = v;}

    //通过path获取servlet
    Servlet::ptr getServlet(const std::string& path);
    //通过path获取模糊匹配servlet
    Servlet::ptr getGlobServlet(const std::string& path);
    //通过path获取servlet
    Servlet::ptr getMatchedServlet(const std::string& path);


    void addServletCreator(const std::string& path, IServletCreator::ptr creator);
    void addGlobServletCreator(const std::string& path, IServletCreator::ptr creator);

    template<class T>
    void addServletCreator(const std::string& path) {
        addServletCreator(path, std::make_shared<ServletCreator<T> >());
    }

    template<class T>
    void addGlobServletCreator(const std::string& path) {
        addGlobServletCreator(path, std::make_shared<ServletCreator<T> >());
    }


    void listAllServletCreator(std::map<std::string, IServletCreator::ptr>& infos);
    void listAllGlobServletCreator(std::map<std::string, IServletCreator::ptr>& infos);

private:
    std::shared_mutex m_sharedMutex;
    //精准匹配 path(/path/xxx) -> servlet
    std::unordered_map<std::string, IServletCreator::ptr> m_datas;  
    //模糊匹配 path(/path/*) -> servlet
    std::vector<std::pair<std::string, IServletCreator::ptr>> m_globs;  
    // 默认servlet，所有路径都没匹配到时使用
    Servlet::ptr m_default;
};


class NotFoundServlet: public Servlet
{
public:
    using ptr = std::shared_ptr<NotFoundServlet>;
    NotFoundServlet(const std::string& name);
    virtual ~NotFoundServlet() {}

    virtual int32_t handle(RequestPtr request
                ,ResponsePtr response) override;
private:
    std::string m_name;
    std::string m_content; //错误内存（消息体），默认返回404
};

#endif //SERVLET_H